package io.youngledo.usb.storage.impl;

import io.youngledo.usb.storage.*;
import io.youngledo.usb.config.TimeoutConfig;
import com.obs.services.ObsClient;
import com.obs.services.ObsConfiguration;
import com.obs.services.model.*;
import com.obs.services.model.S3Bucket;

import java.io.*;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;

/// 华为云OBS存储服务适配器，[地区和终端节点](https://console.huaweicloud.com/apiexplorer/#/endpoint/OBS)
///
public class HuaweiStorageService extends AbstractObjectStorageService {

    private ObsClient obsClient;

    @Override
    public void connect(StorageConfig config) {
        if (config.type() != StorageType.HUAWEI_OBS) {
            throw new IllegalArgumentException("Invalid storage type for Huawei OBS service: " + config.type());
        }

        this.config = config;

        // 创建OBS配置，使用统一的超时配置
        ObsConfiguration obsConfiguration = new ObsConfiguration();
        obsConfiguration.setSocketTimeout(TimeoutConfig.SOCKET_TIMEOUT_MS);
        obsConfiguration.setConnectionTimeout(TimeoutConfig.CONNECTION_TIMEOUT_MS);
        obsConfiguration.setEndPoint(config.endpoint());

        // 设置是否使用HTTPS
        if (config.useSSL()) {
            obsConfiguration.setHttpsOnly(true);
        }

        // 创建OBS客户端
        this.obsClient = new ObsClient(config.accessKey(), config.secretKey(), obsConfiguration);

        // 测试连接 - 尝试列出存储桶
        obsClient.listBuckets(null);
        this.connected = true;
    }

    @Override
    protected void performDisconnect() {
        if (obsClient != null) {
            try {
                obsClient.close();
            } catch (Exception e) {
                // 忽略关闭异常
            }
            obsClient = null;
        }
    }

    @Override
    public List<StorageBucket> listBuckets() {
        checkConnection();
        return obsClient.listBuckets(null)
                .parallelStream().map(bucket -> new StorageBucket(
                        bucket.getBucketName(),
                        bucket.getCreationDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(),
                        null
                )).toList();
    }

    @Override
    public void createBucket(String bucketName) {
        checkConnection();
        CreateBucketRequest request = new CreateBucketRequest(bucketName);
        obsClient.createBucket(request);
    }

    @Override
    public void deleteBucket(String bucketName) {
        checkConnection();
        obsClient.deleteBucket(bucketName);
    }

    @Override
    public List<StorageObject> listObjects(String bucketName, String prefix, boolean recursive) {
        checkConnection();

        List<StorageObject> result = new ArrayList<>();
        ListObjectsRequest request = new ListObjectsRequest(bucketName);
        request.setPrefix(prefix);

        if (!recursive) {
            request.setDelimiter("/");
        }

        ObjectListing objectListing = obsClient.listObjects(request);

        // 处理普通对象
        result.addAll(ObjectStorageHelper.processObjects(
                objectListing.getObjects(),
                prefix,
                ObsObject::getObjectKey,
                (object, key, displayName) -> new StorageObject(
                        key,
                        displayName,
                        object.getMetadata().getContentLength(),
                        object.getMetadata().getLastModified().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(),
                        false,
                        null
                )
        ));

        // 处理公共前缀（目录）
        if (!recursive) {
            result.addAll(ObjectStorageHelper.processCommonPrefixes(
                    objectListing.getCommonPrefixes(),
                    prefix,
                    true  // 移除末尾的斜杠
            ));
        }

        return result;
    }

    @Override
    public void uploadFile(String bucketName, String objectKey, File file) {
        checkConnection();
        PutObjectRequest request = new PutObjectRequest(bucketName, objectKey, file);
        obsClient.putObject(request);
    }

    @Override
    public void uploadFile(String bucketName, String objectKey, InputStream inputStream, long contentLength) {
        checkConnection();
        PutObjectRequest request = new PutObjectRequest(bucketName, objectKey, inputStream);
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(contentLength);
        request.setMetadata(metadata);
        obsClient.putObject(request);
    }

    @Override
    public InputStream downloadFile(String bucketName, String objectKey) {
        checkConnection();
        GetObjectRequest request = new GetObjectRequest(bucketName, objectKey);
        ObsObject object = obsClient.getObject(request);
        return object.getObjectContent();
    }

    @Override
    public void downloadFile(String bucketName, String objectKey, File localFile) {
        checkConnection();
        DownloadFileRequest downloadRequest = new DownloadFileRequest(bucketName, objectKey);
        downloadRequest.setDownloadFile(localFile.getAbsolutePath());
        obsClient.downloadFile(downloadRequest);
    }

    @Override
    public void deleteObject(String bucketName, String objectKey) {
        checkConnection();
        DeleteObjectRequest request = new DeleteObjectRequest(bucketName, objectKey);
        obsClient.deleteObject(request);
    }

    @Override
    public void deleteObjects(String bucketName, List<String> objectKeys) {
        checkConnection();
        DeleteObjectsRequest request = new DeleteObjectsRequest(bucketName);
        for (String key : objectKeys) {
            request.addKeyAndVersion(key);
        }
        obsClient.deleteObjects(request);
    }


    @Override
    public StorageObject getObjectInfo(String bucketName, String objectKey) {
        checkConnection();
        GetObjectMetadataRequest request = new GetObjectMetadataRequest(bucketName, objectKey);
        ObjectMetadata metadata = obsClient.getObjectMetadata(request);

        return new StorageObject(
                objectKey,
                objectKey.substring(objectKey.lastIndexOf('/') + 1),
                metadata.getContentLength(),
                metadata.getLastModified().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(),
                objectKey.endsWith("/"),
                null
        );
    }

    @Override
    public StorageType getStorageType() {
        return StorageType.HUAWEI_OBS;
    }

}